package http

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/smartwalle/alipay/v3"
	app2 "github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"mall-portalv2/conf"
	"mall-portalv2/global"
	"mall-portalv2/internal/model"
	"mall-portalv2/internal/server/ctx"
	"mall-portalv2/library/common"
	"net/http"
	"time"
)

func OrderPayHandlerFunc(c *gin.Context) {
	app := ctx.Gin{C: c}

	uidStr, isUid := c.Get("uid")
	if !isUid {
		global.Log.Error("uid不存在")
		app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, nil)
		return
	}
	UID := common.Str2Int64(fmt.Sprintf("%d", uidStr))

	type RequestBody struct {
		SourceType int64 `json:"sourceType" gorm:"source_type"` // 订单来源：0->PC订单；1->app订单
		BillType   int64 `json:"billType" gorm:"bill_type"`     // 发票类型：0->不开发票；1->电子发票；2->纸质发票
		Way        int   `json:"way"`                           // 付款方式：1->支付宝；2->微信；3->paypal
		OrderId    int64 `json:"orderId"`
	}

	request := RequestBody{}
	if err := common.BindAndCheck(c, &request); err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		app.Response(http.StatusBadRequest, ctx.StatusBadRequest, err)
		return
	}

	global.Log.Info("映射完成", zap.Any("data", request))

	// 订单状态：-1->全部；0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭

	result, err := svc.QueryOmsOrderWhereId(c, request.OrderId, UID)
	if err != nil {
		global.Log.Error("mysql err", zap.Error(err))
		if err == gorm.ErrRecordNotFound {
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, "找不到对应的订单记录")
			return
		} else {
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}
	}

	PayDataResult, err := svc.QueryPayLogsWhereOrderId(c, request.OrderId, request.Way, 0)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			goto next
		} else {
			global.Log.Error("mysql err", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}
	}

	if PayDataResult.ID > 0 && time.Now().Before(PayDataResult.ExpiresTime) {
		if request.Way == 1 {
			// 过期时间还没到的话，直接返回这次pay data的结果
			app.Response(http.StatusOK, ctx.OK, PayDataResult.SendData)
			return
		} else if request.Way == 2 {
			global.Log.Info("")
			PrepayWithRequestPaymentResponseResult := app2.PrepayWithRequestPaymentResponse{}
			if err := json.Unmarshal([]byte(PayDataResult.SendData), &PrepayWithRequestPaymentResponseResult); err != nil {
				global.Log.Error("反序列化有问题", zap.Error(err))
				app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
				return
			}
			// 过期时间还没到的话，直接返回这次pay data的结果
			app.Response(http.StatusOK, ctx.OK, PrepayWithRequestPaymentResponseResult)
			return
		} else {
			// 过期时间还没到的话，直接返回这次pay data的结果
			app.Response(http.StatusOK, ctx.OK, PayDataResult.SendData)
			return
		}
		return
	}

next:
	orderSettingResult, err := svc.QueryOmsOrderSetting(c)
	if err != nil {
		global.Log.Error("mysql err", zap.Error(err))
		if err == gorm.ErrRecordNotFound {
			app.Response(http.StatusBadRequest, ctx.StatusBadRequest, "找不到对应的订单设置记录")
			return
		} else {
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}
	}

	allPrice := result.PayAmount + result.FreightAmount

	if conf.Config.System.AppDev == "test" {
		allPrice = 0.01
	}

	TimeExpire := time.Now().Add(time.Minute * time.Duration(orderSettingResult.NormalOrderOvertime))
	paySn := result.GeneratePaySn()

	if request.Way == 1 {
		global.Log.Info("打印订单详情接口", zap.Any("result", result))
		aliClient, err := alipay.New(conf.Config.AliPay.AppID, conf.Config.AliPay.PrivateKey, conf.Config.AliPay.IsProduction)
		if err != nil {
			global.Log.Error("请求参数不正确", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}

		//  加载应用公钥证书
		if err := aliClient.LoadAppPublicCertFromFile(conf.Config.AliPay.AppCertPublicKey); err != nil {
			global.Log.Error("加载应用公钥证书错误", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}
		// 加载支付宝根证书
		if err := aliClient.LoadAliPayRootCertFromFile(conf.Config.AliPay.AlipayRootCert); err != nil {
			global.Log.Error("加载支付宝根证书错误", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}
		// 加载支付宝公钥证书
		if err := aliClient.LoadAliPayPublicCertFromFile(conf.Config.AliPay.AlipayCertPublicKey_RSA2); err != nil {
			global.Log.Error("加载支付宝公钥证书错误", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}
		//aliClient.ap
		//aliClient.appCertSN

		var p = alipay.TradeAppPay{}
		p.NotifyURL = conf.Config.AliPay.NotifyUrl
		p.ReturnURL = conf.Config.AliPay.NotifyUrl
		p.Subject = result.PromotionInfo
		p.OutTradeNo = result.OrderSn
		p.TotalAmount = fmt.Sprintf("%.2f", allPrice)
		p.ProductCode = "QUICK_APP_WAY"
		// 绝对超时时间，格式为yyyy-MM-dd HH:mm。
		p.TimeExpire = TimeExpire.Format("2006-01-02 15:04")

		resultStr, err := aliClient.TradeAppPay(p)
		if err != nil {
			global.Log.Error("请求参数不正确", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}

		//var payURL = url.String()
		global.Log.Info("data", zap.Any("resul", resultStr))
		// https://openapi.alipaydev.com/gateway.do
		//tmp := strings.TrimPrefix(payURL, "https://openapi.alipaydev.com/gateway.do?")

		insertData, err := svc.CreatePayLogs(c, model.OmsPayLogs{
			MemberId:        UID,
			Type:            0,                  // 预订单类型:0->支付;1->退款
			PayType:         int64(request.Way), // 付款方式：1->支付宝；2->微信；3->paypal
			OrderId:         result.ID,
			PaySn:           paySn,
			OrderSn:         result.OrderSn,
			PaymentTime:     result.PaymentTime,
			DeadlinePayment: result.DeadlinePayment,
			SendData:        resultStr,
			ExpiresTime:     TimeExpire,
		})

		if err != nil {
			global.Log.Error("支付预订单数据写入错误", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}
		global.Log.Info("支付预订单记录完成", zap.Any("id", insertData.ID))

		app.Response(http.StatusOK, ctx.OK, resultStr)
		return
	} else if request.Way == 2 {

		payResult, err := svc.WechatPay(c, result, TimeExpire, allPrice, paySn)
		if err != nil {
			global.Log.Error("生成支付签名失败", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}

		global.Log.Info("wchatPay", zap.Any("resp", payResult), zap.Any("result.OrderSn", result.OrderSn))

		resultData, err := json.Marshal(payResult)
		if err != nil {
			global.Log.Error("序列化有问题", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}

		insertData, err := svc.CreatePayLogs(c, model.OmsPayLogs{
			MemberId:        UID,
			Type:            0,                  // 预订单类型:0->支付;1->退款
			PayType:         int64(request.Way), // 付款方式：1->支付宝；2->微信；3->paypal
			OrderId:         result.ID,
			PaySn:           paySn,
			OrderSn:         result.OrderSn,
			PaymentTime:     result.PaymentTime,
			DeadlinePayment: result.DeadlinePayment,
			SendData:        string(resultData),
			ExpiresTime:     TimeExpire,
		})

		if err != nil {
			global.Log.Error("支付预订单数据写入错误", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
			return
		}
		global.Log.Info("支付预订单记录完成", zap.Any("id", insertData.ID))

		app.Response(http.StatusOK, ctx.OK, payResult)
		return
	}
}
